package engine.game.hud;

import engine.entities.Entity;
import engine.entities.Player;
import engine.game.Tickable;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class StatBlockViewer extends JPanel implements Tickable {

    private static final long serialVersionUID = 1L;

    private JLabel label;
    private SpriteRenderer icon;

    private JPanel header;
    private JPanel iconPanel;
    private JPanel iconWrapper;
    private PropertyDisplayer propsWrapper;
    private JScrollPane propsScrollPane;
    private ActionButtonDisplayer actionPanel;
    private Entity currentEntity;

    private static final Font titleFont = new Font("Arial", Font.BOLD, 16);
    private static final Font propNameFont = new Font("Arial", Font.BOLD, 12);
    private static final Font wordFont = new Font("Arial", Font.PLAIN, 12);

    public StatBlockViewer(Player player) {

        ArrayList<DispProp> props = new ArrayList<>();
        props.add(new DispProp("NAME", "Jip"));
        props.add(new DispProp("ATTACK", "42"));
        props.add(new DispProp("DEFENSE", "39"));

        this.setLayout(new GridBagLayout());

        header = new JPanel();
        header.setLayout(new BoxLayout(header, BoxLayout.LINE_AXIS));

        label = new JLabel("Viewer");
        label.setFont(titleFont);
        label.setHorizontalAlignment(JLabel.CENTER);

        header.add(Box.createHorizontalGlue());
        header.add(label);
        header.add(Box.createHorizontalGlue());

        header.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));

        icon = new SpriteRenderer(player.getStaticSprite(), 3);

        iconPanel = new JPanel();
        iconPanel.setLayout(new BoxLayout(iconPanel, BoxLayout.LINE_AXIS));
        iconPanel.add(Box.createHorizontalGlue());
        iconWrapper = new JPanel();
        iconWrapper.add(icon);
        iconWrapper.setBorder(BorderFactory.createLoweredBevelBorder());
        iconPanel.add(iconWrapper);
        iconPanel.add(Box.createHorizontalGlue());
        header.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
        
        actionPanel = new ActionButtonDisplayer();

        propsWrapper = new PropertyDisplayer();
        propsScrollPane = new JScrollPane(propsWrapper);
        propsScrollPane.setBorder(BorderFactory.createEmptyBorder());

        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.NONE;
        c.weightx = 0.0;
        c.weighty = 0.0;
        c.anchor = GridBagConstraints.PAGE_START;
        this.add(header, c);

        c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 1;
        c.fill = GridBagConstraints.NONE;
        c.weightx = 0.0;
        c.weighty = 0.0;
        c.anchor = GridBagConstraints.PAGE_START;
        this.add(iconPanel, c);
        
        c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 2;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 0.0;
        c.anchor = GridBagConstraints.PAGE_START;
        this.add(actionPanel, c);

        c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 3;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 0.0;
        c.anchor = GridBagConstraints.PAGE_START;
        this.add(propsScrollPane, c);

        c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 4;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.anchor = GridBagConstraints.PAGE_START;
        this.add(Box.createVerticalGlue(), c);
    }

    public void setEntity(Entity ent) {
        currentEntity = ent;
        label.setText(ent.getName());
        icon.setIcon(ent.getSprite(), 3);

        propsWrapper.removeAll();
        DispProp[] props = ent.getDisplayProperties();

        if (props != null) {
            for (DispProp prop : props) {
                propsWrapper.addProperty(prop);
            }
        }

        actionPanel.removeAll();
        ViewerAction[] actions = ent.getViewerActions();
        if (actions != null) {
            for (ViewerAction action : actions) {
                actionPanel.addActionButton(action);
            }
        }
        
        this.revalidate();
    }

    public Entity getEntity() {
        return currentEntity;
    }
    
    @Override
    public void tick() {
        actionPanel.tick();
    }

    private class ActionButtonDisplayer extends JPanel implements Tickable {

        private int nextRow = 0;
        private List<ViewerActionButton> buttons;

        public ActionButtonDisplayer() {
            this.buttons = new ArrayList<>();
            this.setLayout(new GridBagLayout());
        }

        public void addActionButton(ViewerAction action) {
            ViewerActionButton button = new ViewerActionButton(action);
            GridBagConstraints c = new GridBagConstraints();
            c.gridx = 0;
            c.gridy = nextRow;
            c.weightx = 0.0;
            c.weighty = 0.0;
            c.insets = new Insets(5, 5, 0, 5);
            c.fill = GridBagConstraints.HORIZONTAL;
            this.add(button, c);
            buttons.add(button);
            nextRow++;
        }

        @Override
        public void removeAll() {
            super.removeAll();
            nextRow = 0;
            buttons = new ArrayList<>();
        }

        @Override
        public void tick() {
            if (buttons.isEmpty()) {
                return;
            }
            
            for (ViewerActionButton button : buttons) {
                button.tick();
            }
        }

    }

    private class PropertyDisplayer extends JPanel {

        private int nextRow = 0;

        public PropertyDisplayer() {
            this.setLayout(new GridBagLayout());
        }

        public void addProperty(DispProp prop) {
            GridBagConstraints c;

            c = new GridBagConstraints();
            c.gridx = 0;
            c.gridy = nextRow;
            c.weightx = 0.0;
            c.weighty = 0.0;
            c.anchor = GridBagConstraints.NORTHWEST;
            c.fill = GridBagConstraints.BOTH;
            c.insets = new Insets(5, 5, 0, 5);
            JLabel titleLabel = new JLabel(prop.key);
            titleLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
            titleLabel.setFont(propNameFont);
            this.add(titleLabel, c);

            c = new GridBagConstraints();
            c.gridx = 1;
            c.gridy = nextRow;
            c.weightx = 1.0;
            c.weighty = 0.0;
            c.anchor = GridBagConstraints.NORTHWEST;
            c.fill = GridBagConstraints.BOTH;
            c.insets = new Insets(5, 5, 0, 5);
            JLabel fieldLabel = new JLabel(prop.value);
            fieldLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
            fieldLabel.setFont(wordFont);
            this.add(fieldLabel, c);

            nextRow++;
        }

        @Override
        public void removeAll() {
            super.removeAll();
            nextRow = 0;
        }

    }

    public static class DispProp {

        private String key;
        private String value;

        public DispProp(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public String key() {
            return key;
        }

        public String value() {
            return value;
        }
    }

    public static abstract class ViewerAction {

        protected String name;

        public ViewerAction(String name) {
            this.name = name;
        }

        public final String getName() {
            return name;
        }

        public abstract boolean canBeInvoked();

        public abstract void performAction();

    }

    public static class ViewerActionButton extends JButton implements Tickable, ActionListener {

        private ViewerAction action;

        public ViewerActionButton(ViewerAction action) {
            this.action = action;
            this.setText(action.getName());
            this.addActionListener(this);
        }

        @Override
        public void tick() {
            this.setEnabled(action.canBeInvoked());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            action.performAction();
        }

    }

}
